package com.sh.data.engine.domain.authority.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.domain.authority.model.domain.ApplicationKeyDomain;
import com.sh.data.engine.domain.authority.service.AccessKeyService;
import com.sh.data.engine.domain.base.model.PageResult;
import com.sh.data.engine.domain.base.model.UserContext;
import com.sh.data.engine.domain.management.model.param.BaseQueryParam;
import com.sh.data.engine.domain.util.ConvertUtil;
import com.sh.data.engine.domain.workspace.index.model.mapper.AccessKeyDomainMapper;
import com.sh.data.engine.repository.dao.authority.AccessKeyMapper;
import com.sh.data.engine.repository.dao.authority.entity.ApplicationKeyEntity;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.security.SecureRandom;

@Service
public class AccessKeyServiceImpl extends ServiceImpl<AccessKeyMapper, ApplicationKeyEntity> implements AccessKeyService {

    private static final String CHAR_LOWER = "abcdefghijklmnopqrstuvwxyz";
    private static final String CHAR_UPPER = CHAR_LOWER.toUpperCase();
    private static final String NUMBER = "0123456789";
    private static final String DATA_FOR_RANDOM_STRING = CHAR_LOWER + CHAR_UPPER + NUMBER;
    private static final SecureRandom random = new SecureRandom();

    @Autowired
    private AccessKeyDomainMapper accessKeyDomainMapper;

    /**
     * 生成指定长度的随机字符串
     *
     * @param length 字符串长度
     * @return 随机字符串
     */
    public static String generateRandomString(int length) {
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            int rndCharAt = random.nextInt(DATA_FOR_RANDOM_STRING.length());
            char rndChar = DATA_FOR_RANDOM_STRING.charAt(rndCharAt);
            sb.append(rndChar);
        }
        return sb.toString();
    }

    /**
     * 生成Access Key (AK)
     *
     * @return 16位的AK
     */
    public static String generateAccessKey() {
        return generateRandomString(16);
    }

    /**
     * 生成Secret Key (SK)
     *
     * @return 30位的SK
     */
    public static String generateSecretKey() {
        return generateRandomString(30);
    }

    public PageResult<ApplicationKeyDomain> getAccessKeyValid() {
        try {
            LambdaQueryWrapper<ApplicationKeyEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ApplicationKeyEntity::getUserId, UserContext.getUserId()).eq(ApplicationKeyEntity::getEnabled, 1);
            Page<ApplicationKeyEntity> page = this.page(new Page<>(1, 1), wrapper);
            PageResult<ApplicationKeyEntity> dataSourcePageResult = PageResult.convert(page);
            dataSourcePageResult.getResult().forEach(e -> e.setSecretKey(null));
            return ConvertUtil.convertPageInfo(dataSourcePageResult, ApplicationKeyDomain.class);
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        }

    }

    @Override
    public ApplicationKeyDomain createAccessKey(String description) {
        if (!getAccessKeyValid().getResult().isEmpty()) {
            throw new BusinessException("You have already created an AK, please disable or delete it first");
        }
        String accessKey = generateAccessKey();
        String secretKey = generateSecretKey();
        ApplicationKeyEntity entity = new ApplicationKeyEntity(UserContext.getUserId(), accessKey, secretKey, description, 1);
        save(entity);
        ApplicationKeyDomain map = accessKeyDomainMapper.map(entity);
        map.setAccessKey(null);
        return map;

    }

    /**
     * 返回启用和禁用全部aksk
     *
     * @return
     */
    @Override
    public PageResult<ApplicationKeyDomain> getAccessKey(BaseQueryParam param) {
        LambdaQueryWrapper<ApplicationKeyEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ApplicationKeyEntity::getUserId, UserContext.getUserId());
        Page<ApplicationKeyEntity> page = this.page(new Page<>(param.getPageNum(), param.getPageSize()), wrapper);
        PageResult<ApplicationKeyEntity> dataSourcePageResult = PageResult.convert(page);
        //针对dataSourcePageResult中对象转换
        dataSourcePageResult.getResult().forEach(e -> e.setSecretKey(null));
        return ConvertUtil.convertPageInfo(dataSourcePageResult, ApplicationKeyDomain.class);
    }


    /**
     * @param accessKey
     * @return
     */
    @Override
    public int updateAKState(String accessKey) {
        if (!getAccessKeyValid().getResult().isEmpty()) {
            if (accessKey.equals(getAccessKeyValid().getResult().get(0).getAccessKey())) {
                updateRowState(accessKey);
            } else {
                throw new BusinessException("You have already enabled an AK, please disable or delete it first");
            }
        } else {
            updateRowState(accessKey);
        }
        return 1;
    }

    public void updateRowState(String accessKey) {
        LambdaQueryWrapper<ApplicationKeyEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ApplicationKeyEntity::getAccessKey, accessKey);
        ApplicationKeyEntity entity = this.baseMapper.selectOne(wrapper);
        LambdaUpdateWrapper<ApplicationKeyEntity> lambdaUpdateWrapper = new UpdateWrapper<ApplicationKeyEntity>().lambda();
        lambdaUpdateWrapper.set(ApplicationKeyEntity::getEnabled, entity.getEnabled() == 1 ? 0 : 1)
                .eq(ApplicationKeyEntity::getAccessKey, accessKey);
        update(new ApplicationKeyEntity(), lambdaUpdateWrapper);
    }

    @Override
    public int updateDescription(String description, String accessKey) {
        LambdaUpdateWrapper<ApplicationKeyEntity> lambdaUpdateWrapper = new UpdateWrapper<ApplicationKeyEntity>().lambda();
        lambdaUpdateWrapper.set(ApplicationKeyEntity::getDescription, description)
                .eq(ApplicationKeyEntity::getAccessKey, accessKey);
        update(new ApplicationKeyEntity(), lambdaUpdateWrapper);
        return 1;
    }

    @Override
    public int deleteAccessKey(String accessKey) {
        LambdaQueryWrapper<ApplicationKeyEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ApplicationKeyEntity::getAccessKey, accessKey);
        return this.baseMapper.delete(wrapper);
    }
}
